package hudson.plugins.aspen;

import hudson.model.ModelObject;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.Attributes;
import org.xml.sax.SAXException;
import org.xml.sax.helpers.DefaultHandler;

public class FeatureSupportReport implements ModelObject, Serializable{

	private static final long serialVersionUID = -7685160726898758694L;
	
	List<String> features;
	List<String> platforms;
	Map<Pair<String, String>, Boolean> success;
	
	public FeatureSupportReport(File compositeReportFile) {
		features = new ArrayList<String>();
		platforms = new ArrayList<String>();
		success = new HashMap<Pair<String,String>, Boolean>();
		try {
			FeatureReportHandler saxHandler = new FeatureReportHandler(this);
			
			SAXParserFactory factory = SAXParserFactory.newInstance();
	        SAXParser saxParser = factory.newSAXParser();
	        
	        saxParser.parse( compositeReportFile, saxHandler );
		} catch (IOException e) {
			e.printStackTrace();
		} catch (SAXException e) {
			e.printStackTrace();
		} catch (ParserConfigurationException e) {
			e.printStackTrace();
		}
		
	}

	public List<String> getFeatures(){
		return Collections.unmodifiableList(features);
	}
	
	public List<String> getPlatforms(){
		return Collections.unmodifiableList(platforms);
	}
	
	public Boolean getSuccess(String feature, String platform){
		Pair<String, String> key = new Pair<String, String>(feature, platform);
		Boolean ret = success.get(key);
		return ret;
	}
	
	public String getHexColorOfSuccess(String feature, String platform){
		Boolean success = getSuccess(feature, platform);
		if(success == null){
			return "#FFFFFF";
		} else if (success) {
			return "#AAFFAA";
		} else {
			return "#FFAAAA";
		}
	}
	
	public String getDisplayName() {
		return "Cross Platform Feature Support";
	}

	public int getPassed() {
		int count = 0;
		for(Boolean bool : success.values()){
			if(Boolean.TRUE.equals(bool)){
				count++;
			}
		}
		return count;
	}

	public int getTotal(){
		return (features.size() * platforms.size());
	}
	
	public int getFailed() {
		return getTotal() - getPassed();
	}

	public boolean hasMixedSuccess(String feature){
		return false;
	}
}

class FeatureReportHandler extends DefaultHandler{

	FeatureSupportReport report;
	boolean startOfRow;
	boolean startOfTable;
	int col;
	String lastReadFeature;
	String lastReadPlatorm;
	boolean storePlatformChars;
	boolean storeFeatureChars;
	
	public FeatureReportHandler(FeatureSupportReport report) {
		super();
		this.report = report;
		startOfRow = false;
		startOfTable = false;
		col = 0;
		lastReadFeature = "";
		lastReadPlatorm = "";
		storePlatformChars = false;
		storeFeatureChars = false;
	}

	@Override
	public void startElement(String uri, String localName, String qName,
			Attributes attributes) throws SAXException {
		
		if(qName.equals("td")){
			if(startOfTable && startOfRow){
				// do nothing on empty cell
			} else if(startOfTable) {
				// add next characters event to platform names
				storePlatformChars = true;
			} else if(startOfRow){
				// add next characters event to features names
				// and set current
				storeFeatureChars = true;
				col = 0;
			} else {
				// set key <last feature> <platform at col> to
				// True on green, False on red/other
				Boolean bool = Boolean.FALSE;
				if( attributes != null && "background:#AAFFAA;".equals(attributes.getValue("style")) ){
					bool = Boolean.TRUE;
				}
				report.success.put(new Pair<String, String>(lastReadFeature, report.platforms.get(col)), bool);
				col++;
			}
			startOfRow = false;
		} else if(qName.equals("tr")){
			startOfRow = true;
		} else if(qName.equals("table")){
			startOfTable = true;
		}
	}

	@Override
	public void endElement(String uri, String localName, String qName)
			throws SAXException {
		if(qName.equals("tr")){
			startOfTable = false;
			lastReadFeature = "";
		} if(qName.equals("td")){
			if(storePlatformChars)
				report.platforms.add(lastReadPlatorm);
			if(storeFeatureChars)
				report.features.add(lastReadFeature);
			storeFeatureChars = false;
			storePlatformChars = false;
			lastReadPlatorm = "";
		}
	}

	@Override
	public void characters(char[] chars, int start, int length)
			throws SAXException {
		if(storeFeatureChars || storePlatformChars){
			String characters = new String(Arrays.copyOfRange(chars, start, start+length));
			if(storeFeatureChars){
				lastReadFeature += characters;
			} else if (storePlatformChars) {
				lastReadPlatorm += characters;
			}
		}
	}
	
}


class Pair<S, T> {
	S s;
	T t;
	public Pair(S s, T t){
		this.s = s;
		this.t = t;
	}
	@Override
	public int hashCode() {
		final int prime = 31;
		int result = 1;
		result = prime * result + ((s == null) ? 0 : s.hashCode());
		result = prime * result + ((t == null) ? 0 : t.hashCode());
		return result;
	}
	@Override
	public boolean equals(Object obj) {
		if (this == obj)
			return true;
		if (obj == null)
			return false;
		if (getClass() != obj.getClass())
			return false;
		Pair other = (Pair) obj;
		if (s == null) {
			if (other.s != null)
				return false;
		} else if (!s.equals(other.s))
			return false;
		if (t == null) {
			if (other.t != null)
				return false;
		} else if (!t.equals(other.t))
			return false;
		return true;
	}
	
}
